#if !defined(MEM_POOL_H)
#define MEM_POOL_H

template <int ObjectSize, int NumOfObjects = 20>
class mempool
{
private:
    /// @brief 每个内存节点大小
    const int ItemSize;

    /// @brief 空闲节点结构体
    struct FreeNode
    {
        FreeNode *pNext;
        char data[ObjectSize];
    };

    /// @brief 每个内存块大小
    const int MemBlockSize;

    /// @brief 内存块结构体
    struct MemBlock
    {
        MemBlock *pNext;
        FreeNode data[NumOfObjects];
    };

    /// @brief 空闲块头节点
    /// @note 若该节点为空则表明没有可用的空闲节点，需重分配新节点
    FreeNode *freeNodeHeader;

    /// @brief 内存块头节点
    MemBlock *memBlockHeader;

public:
    // ItemSize 对象的大小+空闲节点指针大小
    mempool() : ItemSize(ObjectSize + sizeof(FreeNode *)),
                MemBlockSize(sizeof(MemBlock *) + NumOfObjects * (ObjectSize + sizeof(FreeNode *)))
    {
        freeNodeHeader = nullptr;
        memBlockHeader = nullptr;
    };

    ~mempool()
    {
        MemBlock *ptr;
        while (memBlockHeader)
        {
            ptr = memBlockHeader->pNext;
            delete memBlockHeader;
            memBlockHeader = ptr;
        }
    };

    /// @brief 分配空闲节点
    /// @tparam ObjectSize
    /// @tparam NumOfObjects
    /// @return 分配的内存地址
    void *malloc();

    /// @brief 释放已经分配的节点
    /// @tparam ObjectSize
    /// @tparam NumOfObjects
    /// @param void* 要回收的节点地址
    void free(void *);
};

template <int ObjectSize, int NumOfObjects>
void *mempool<ObjectSize, NumOfObjects>::malloc()
{
    // 无空闲节点
    if (freeNodeHeader == nullptr)
    {
        MemBlock *newBlock = new MemBlock;
        // 设置内存块第一个节点为空闲节点链表的最后一个
        newBlock->data[0].pNext = nullptr;
        for (int i = 1; i < NumOfObjects; ++i)
            newBlock->data[i].pNext = &newBlock->data[i - 1];
        freeNodeHeader = &newBlock->data[NumOfObjects - 1];
        newBlock->pNext = memBlockHeader;
    }
    // 返回空节点闲链表的第一个节点（从链表中删除）
    void *freeNode = freeNodeHeader;
    freeNodeHeader = freeNodeHeader->pNext;
    return freeNode;
}

template <int ObjectSize, int NumOfObjects>
void mempool<ObjectSize, NumOfObjects>::free(void *p)
{
    FreeNode *pNode = (FreeNode *)p;
    // 将回收的节点插入空闲节点头部
    pNode->pNext = freeNodeHeader;
    freeNodeHeader = pNode;
}

#endif // MEM_POOL_H
